Conversation
ZK support via MultiMegaZKFlavor with masking polynomials, Libra commitments, and SmallSubgroupIPA. Recursive verification for both MultiMega and MultiMegaZK with Ultra and Mega outer builders, including proof_length specializations for recursive flavors. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Reorder InterleavedWitnessCommitments so unshiftable groups come first and the 3 shiftable groups (W1, W6, W9) are contiguous at the end, enabling the existing remove_repeated_commitments mechanism to merge shifted/unshifted commitment scalars. This saves 3 points from the final PCS MSM. Key changes: - Reorder InterleavedWitnessCommitments_ members and get_unshifted_groups - Enable REPEATED_COMMITMENTS in MultiMega and MultiMegaZK flavors - Update FINAL_PCS_MSM_SIZE to reflect the reduced MSM size - Alias InterleavedWitnessCommitments/PrecomputedCommitments in recursive flavor from native to avoid duplication - Simplify remove_repeated_commitments: remove has_zk parameter, use absolute indices from RepeatedCommitmentsData directly - Pre-bake Shplemini offset into REPEATED_COMMITMENTS indices across all flavors (Ultra, Mega, ECCVM, Translator, MultiMega + ZK variants) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
MegaFlavor using multiPCS
MegaFlavor using multiPCSMegaFlavors using multiPCS
…d translator ordering - MegaZKFlavor BS=1: HasGeminiMasking=false, no masking entities, -1 REPEATED_COMMITMENTS shift - oink prover/verifier: use flavor_has_gemini_masking gate for masking commitment - batched translator verifier: translator-first unshifted ordering, no MegaZK masking - honk_transcript test: use flavor_has_gemini_masking for manifest gate - ultra_verifier: use flavor_has_gemini_masking in build_pcs_commitments
Replace persistent group buffers with on-the-fly interleaved polynomial construction. Entities are allocated individually (same memory as BS=1). Interleaved buffers are built transiently for commitment and PCS. Key changes: - Extract rho from Gemini/Shplemini into prover call sites - Add pippenger_interleaved + commit_interleaved for buffer-free MSM - BS>1 PCS: pre-batch groups into F/G with rho, free entities, manual Gemini - VK construction uses commit_interleaved (no interleaved buffers) - Remove group_buffers_, allocate_interleaved_groups, group_buffer_for Peak memory at 2^19 BS=4: 825 MiB (was 1848 MiB with group buffers).
Replace all if-constexpr BS branching in oink with unified group-based iteration using OinkWitnessRounds_<BS> descriptors and commit_interleaved<BS>. - Add OinkWitnessRounds_<1> and OinkWitnessRounds_<4> with per-round group descriptors (entity pointers + labels) for wires, lookup, inverses, z_perm - Add OinkGroupDescriptor<Ptr> as the shared descriptor type - commit_interleaved<1> delegates to commit() (no temp buffer) - Oink prover: commit_round_groups iterates groups uniformly for all BS - Oink verifier: receive_round_groups iterates groups uniformly for all BS - Remove CommitmentLabels and InterleavedCommitmentLabels from oink - Adding BS=2 requires only OinkWitnessRounds_<2> — zero oink code changes
Add MegaFlavor_<2> (DualMegaFlavor) with groups of 2 polynomials per interleaved commitment: 16 precomputed groups, 15 witness groups (4 shiftable), INTERLEAVING_LOG_K=1. Includes ZK variant, recursive flavors, all template instantiations, and test coverage.
Templatize UltraFlavor_ and UltraZKFlavor_ on BATCH_SIZE, mirroring MegaFlavor_. Add UltraFlavor_<2> (DualUltraFlavor) with 14 precomputed groups, 5 witness groups (3 shiftable), INTERLEAVING_LOG_K=1. Includes ZK variant, recursive flavors, template instantiations, and test coverage.
MegaFlavors using multiPCSReview fixes: - info() → vinfo() in ultra_verifier.cpp - add DualUltra flavors to IsUltraHonk Starknet branch - fix stale comments in claim_batcher.hpp and mega_zk_flavor.hpp - add missing get_shiftable() const to BS=2/BS=4 ZK witness commitments - hoist r_inv_shift computation in gemini.hpp - restore static_assert(MAX_PARTIAL_RELATION_LENGTH == 7) Test coverage: - add DualUltraFlavor + DualUltraZKFlavor to UltraHonkTests type list (also rom_ram.test.cpp and lookup.test.cpp for consistent type lists) - remove standalone DualUltraHonkTests::Basic (now covered by shared suite) - skip ANonZeroPolynomialIsAGoodPolynomial for BS>1 (strided views)
federicobarbacovi
left a comment
There was a problem hiding this comment.
Looks great! A lot of comments but nothing major. Thanks for this!
| } | ||
|
|
||
| // Add hiding op (required before creating the builder) | ||
| eccvm_test_utils::add_hiding_op_for_test(op_queue); |
There was a problem hiding this comment.
WHy was this not needed before?
| */ | ||
| template <typename Flavor> | ||
| template <typename PolyDescs, typename CommDescs> | ||
| void OinkProver<Flavor>::commit_round_groups(const PolyDescs& poly_groups, |
| static constexpr size_t INTERLEAVING_LOG_K = (BATCH_SIZE_ <= 1) ? 0 | ||
| : (BATCH_SIZE_ <= 2) ? 1 | ||
| : (BATCH_SIZE_ <= 4) ? 2 | ||
| : 3; |
There was a problem hiding this comment.
Should we ever hit the 3 case?
| * @brief ZK-specific masking entities, specialized per (DataType, BATCH_SIZE, HasZK). | ||
| * | ||
| * - (any BS, HasZK=false): empty | ||
| * - (BS=1, HasZK=true): single gemini_masking_poly |
There was a problem hiding this comment.
You're missing BS=2 here and in various other places in the comments
| interleaved_precomputed_4, // P₅: [sigma_2, sigma_3, sigma_4, id_1] | ||
| interleaved_precomputed_5, // P₆: [id_2, id_3, id_4, table_1] | ||
| interleaved_precomputed_6, // P₇: [table_2, table_3, table_4, lagrange_first] | ||
| interleaved_precomputed_7) // P₈: [lagrange_last, lagrange_ecc_op, databus_id] (3 polys) |
There was a problem hiding this comment.
Missing a zero at the end of this group
| const size_t total_size = n * batch_size; | ||
|
|
||
| // Build interleaved scalar array: for logical index i, place chunk_j at position batch_size*i + j. | ||
| std::vector<Fr> interleaved_scalars(total_size, Fr::zero()); |
There was a problem hiding this comment.
In the function description you say you don't materialize the interleaved buffer but then you construct this vector, aren't these two statements in contradiction?
| EXPECT_EQ(cc.size(), 1); | ||
|
|
||
| // Expected variables in one gate: | ||
| // TODO: MultiMega oink verifier receives 4 individual ecc_op_wire commitments for merge protocol |
There was a problem hiding this comment.
I think this is a runaway comment. However, what is correct is that we wouldn't be able to set Flavor = DualMegaFlavor in Chonk at the moment because the Merge is not integrated with it, maybe it's worth pointing out
| batched_unshifted = std::move(extended); | ||
| } | ||
| if (!batched_shifted_tail_.is_empty()) { | ||
| batched_to_be_shifted += batched_shifted_tail_; |
There was a problem hiding this comment.
Why does this not need to be extended?
| batched_to_be_shifted *= r_inv_shift; // G = G/r^k | ||
|
|
||
| A_0_pos += batched_to_be_shifted; // A₀₊ += G/r^k | ||
| // A₀₋(X) = F(X) + (-1)^k · G(X)/r^k so that A₀₋(-r) = A₀(-r) |
There was a problem hiding this comment.
| // A₀₋(X) = F(X) + (-1)^k · G(X)/r^k so that A₀₋(-r) = A₀(-r) | |
| // A₀₋(X) = F(X) + (-1)^k · G(X)/r^k since (-r)^k = (-1)^k · r^k. For odd k: subtract. For even k: add. |
| MEGA_ZK_ORIG, // MegaZK original: witness start in unshifted | ||
| MEGA_ZK_DUP, // MegaZK duplicate: mega_shifted start in shifted | ||
| S, // MegaZK count | ||
| 2 /* shplemini_offset: Q + translator_masking_poly */); |
There was a problem hiding this comment.
Where is the 2 coming from?
Summary
Adds parameterized polynomial interleaving to
MegaandUltraproving systems. Instead of committing to each polynomial individually (BS = 1), polynomials are grouped into interleaved commitments of sizeBS = 2orBS = 4, reducing the number of commitments and shrinking the recursive verifier circuit—at the cost of additional PCS work.Key changes
MegaFlavor_<BS>andUltraFlavor_<BS>on interleaving batch sizeBS = 2(DualMegaFlavor,DualUltraFlavor) andBS = 4(MultiMegaFlavor) with full ZK and recursive flavor variantsBS-agnosticOinkProver/OinkVerifier— no branching on batch sizecommit_interleaved<BS>in commitment key for batchedPippengerGeminigeneralized for arbitrary shift exponent (G / X^kwherek = BS)Prover Benchmarks (8 cores, wall time)
Prover overhead is dominated by additional
Geminifold rounds onBS * n-sized group buffers. Memory overhead is modest (~5% forBS = 2, ~27–33% forBS = 4).Recursive Verifier Circuit Size (
UltraCircuitBuilder,DefaultIO)Test plan
ultra_honk_tests—DualUltra/DualUltraZKadded toUltraHonkTests, lookup, androm_ramsuitesultra_honk_tests—DualMega/DualMegaZK/MultiMegaadded toMegaHonkTests(prove/verify, interleaved storage, transcript manifest)stdlib_honk_verifier_tests— recursive verification for allDualUltra/DualMega/MultiMegaflavors withUltraCircuitBuilder